/*
 *      PPP   EEEE  RRR    SSS   OO   NN  N   AA   L
 *      P  P  Eeee  R  R  Sss   O  O  N N N  A  A  L
 *      PPP   E     RRR      S  O  O  N N N  AAAA  L
 *      P     EEEE  R  R  SSS    OO   N  NN  A  A  LLLL
 *
 *      BBB    AA   RRR
 *      B__B  A  A  R  R
 *      B  B  AAAA  RRR
 *      BBB   A  A  R  R		A Plugin for Pidgin
 *      ----------------------------------------------------
 *
 *      AUTHORS
 *      =======
 * 
 *      Craig Harding <craigwharding@gmail.com>
 *        Main Developer
 *      Wolter Hellmund <wolterh6@gmail.com>
 *        Idea man
 *        Developer assistant
 *
 *      Copyright 2008-2009 Craig Harding & Wolter Hellmund
 *      ----------------------------------------------------
 * 
 *      LICENSE
 *      =======
 *
 *      This program is free software; you can redistribute it and/or modify
 *      it under the terms of the GNU General Public License as published by
 *      the Free Software Foundation; either version 2 of the License, or
 *      (at your option) any later version.
 *      
 *      This program is distributed in the hope that it will be useful,
 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *      GNU General Public License for more details.
 *      
 *      You should have received a copy of the GNU General Public License
 *      along with this program; if not, write to the Free Software
 *      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 *      MA 02110-1301, USA.
 * 
 */

#define PURPLE_PLUGINS

#ifndef G_GNUC_NULL_TERMINATED
#	if     __GNUC__ >= 4
#		define G_GNUC_NULL_TERMINATED __attribute__((__sentinel__))
#	else
#		define G_GNUC_NULL_TERMINATED
#	endif
#endif

#include <glib.h>
#include <gmodule.h>
#include <string.h>

#include "plugin.h"
#include "signals.h"
#include "version.h"

#include "gtkblist.h"
#include "gtkstatusbox.h"
#include "gtkplugin.h"
#include "gtkprefs.h"
#include "prpl.h"
#include "request.h"
#include "debug.h"
#include "gtkutils.h"

#include "buddyicon.h"

#ifdef _WIN32
	#include "win32dep.h"
#endif

// pidgin_interface structure
struct _pidgin_interface {
	/** Pidgin interface commonly used widgets struct */
	GtkWindow *window;
	PidginBuddyList *blist;
	PidginStatusBox *statusbox;
} pidgin_interface;

struct _personal_bar {
	/** Specific struct for shared objects of the personal bar */
	PurplePlugin *plugin;
	// Account stuff
	PurpleAccount* jabber_account;
		PurpleConnection *jabber_connection;
	PurpleAccount* msn_account;
		PurpleConnection *msn_connection;
	PurpleAccount* msn_pecan;
		PurpleConnection *msn_pecan_connection;
	// Account data
	char *name;
		char *name_markup;
		char *name_markup_hover;
	char *personal_message;
		char *personal_message_markup;
		char *personal_message_markup_hover;
	PurpleStatus *status;
} personal_bar;

struct _personal_bar_c_interface {
	/** Specific struct for Craig's personal bar */
	gboolean installed;
	GtkWidget *hbox;
		GtkWidget *buddy_icon;
			GtkWidget *buddy_icon_event_box;
			GdkPixbuf *buddy_icon_pixbuf;
			GdkPixbuf *buddy_icon_pixbuf_hovered;
			void (*buddy_icon_refresh) ();
			void (*buddy_icon_clicked) ();
			void (*buddy_icon_hovered) ();
			void (*buddy_icon_unhovered) ();
		GtkWidget *vbox;
			//GtkWidget *event_box; <- Not sure if needed.
			GtkWidget *name_and_status_box;
				GtkWidget *name_label;
					GtkWidget *name_button;
					void (*name_label_clicked) ();
					void (*name_label_hovered) ();
					void (*name_label_unhovered) ();
				GtkWidget *name_entry;
					void (*name_entry_activate) ();
					void (*name_entry_deactivate) ();
				GtkWidget *status_button;
					void (*status_button_update) (PurpleAccount *, PurpleStatus *, PurpleStatus *);
					void (*status_button_clicked) ();
			GtkWidget *personal_message_label;
				#define EMPTY_MESSAGE "<Click to set personal message>"
				GtkWidget *personal_message_button;
				void (*personal_message_label_clicked) ();
				void (*personal_message_label_hovered) ();
				void (*personal_message_label_unhovered) ();
			GtkWidget *personal_message_entry;
				void (*personal_message_entry_activate) ();
				void (*personal_message_entry_deactivate) ();
} personal_bar_c_interface;

struct _personal_bar_w_interface {
	/** Specific struct for Wolter's personal bar */
	gboolean installed;
	GtkWidget *hbox;
		GtkWidget *buddy_icon;
			GdkPixbuf *buddy_icon_pixbuf;
			GdkPixbuf *buddy_icon_pixbuf_hovered;
			void (*buddy_icon_refresh) ();
			void (*buddy_icon_clicked) ();
		GtkWidget *vbox;
			GtkWidget *name_label;
				GtkWidget *name_button;
				void (*name_label_clicked) ();
				void (*name_label_hovered) ();
				void (*name_label_unhovered) ();
			GtkWidget *name_entry;
				void (*name_entry_activate) ();
				void (*name_entry_deactivate) ();
				PangoAttrList *name_style;
			GtkWidget* statusbox;
} personal_bar_w_interface;

// Function declarations
static void init_plugin (PurplePlugin *);
static gboolean plugin_load (PurplePlugin *);
static gboolean plugin_unload (PurplePlugin *);
	// Signals
void signals_connect ();

void status_update ();
void status_online ();
void status_signing_on ();
void status_signing_off ();
void name_update ();
	// Craig's personal bar callbacks
		/* Naming:
		 * c for Craig's
		 * initials of callback function pointers
		 * 	in personal_bar_c_interface struct.
		 */
void c_bir ();
void c_bic ();
void c_bih ();
void c_biu ();
void c_nlc ();
void c_nlh ();
void c_nlu ();
void c_nea ();
void c_ned ();
void c_sbc ();
void c_sbu ();
void c_pmlc ();
void c_pmlh ();
void c_pmlu ();
void c_pmea ();
void c_pmed ();
	// Wolter's personal bar callbacks
		// Naming is same as in Craig's, but w for Wolter
void w_bir ();
void w_bic ();
void w_nlc ();
void w_nlh ();
void w_nlu ();
void w_nea ();
void w_ned ();
//	Global data functions functions
void global_name_get (GtkLabel *);
void global_name_set (const char *, GtkLabel *);
	void global_name_set_jabber ();
	void global_name_set_msn ();
void global_pmsg_get (GtkLabel *);
void global_pmsg_set (const char *, GtkLabel *);
	void global_pmsg_set_jabber ();
	void global_pmsg_set_man ();
void global_buddy_icon_refresh ();
void global_buddy_icon_select ();
	// Personal bar functions
void pidgin_interface_construct ();
void personal_bar_init ();
void personal_bar_get_accounts ();
void personal_bar_prefs_apply ();
void personal_bar_install ();
	void personal_bar_c_install ();
		void personal_bar_c_signals_connect ();
		void personal_bar_c_callbacks_connect ();
	void personal_bar_w_install ();
		void personal_bar_w_signals_connect ();
		void personal_bar_w_callbacks_connect ();
void personal_bar_uninstall ();
	void personal_bar_c_uninstall ();
	void personal_bar_w_uninstall ();
// Common methods
void stylize (GtkLabel *, const char *);
void hover (GtkWidget *, gboolean);
	// From GNOME Panel
static void do_colorshift (GdkPixbuf *dest, GdkPixbuf *src, int shift);
// Plugin data
static PurplePluginInfo info;
static PurplePluginUiInfo preferences;
static PurplePluginPrefFrame *preferences_make_window (PurplePlugin *);
void preferences_init ();
void preferences_apply ();

// Plugin information
#define PLUGIN_ID				"gtk-harding&hellmund-personalbar"
#define PLUGIN_NAME			"Personal Bar"
#define PLUGIN_VERSION	"0.1 (svn)"
#define PLUGIN_INFO			"Gives you a bar to set your global nickname, display and status."
#define PLUGIN_AUTHOR		"Craig Harding <craigwharding@gmail.com>, Wolter Hellmund <wolterh6@gmail.com"
#define PLUGIN_WEBSITE	"Not available"

static PurplePluginInfo info = {
	PURPLE_PLUGIN_MAGIC,
	PURPLE_MAJOR_VERSION,
	PURPLE_MINOR_VERSION,
	PURPLE_PLUGIN_STANDARD,
	PIDGIN_PLUGIN_TYPE,
	0,
	NULL,
	PURPLE_PRIORITY_DEFAULT,

	PLUGIN_ID,
	PLUGIN_NAME,
	PLUGIN_VERSION,

	PLUGIN_INFO,
	PLUGIN_INFO,
	PLUGIN_AUTHOR,
	PLUGIN_WEBSITE,

	plugin_load,
	plugin_unload,
	NULL,

	NULL,
	NULL,
	&preferences,
	NULL,
	
	NULL,
	NULL,
	NULL,
	NULL
};

// Preferences
//	Routes
#define PREF_PREFIX	"/plugins/gtk/" PLUGIN_ID
#define PREF_STATUSBOX_HIDE 		PREF_PREFIX "/statusbox_hide"
#define PREF_PBAR								PREF_PREFIX "/personalbar"
#define PREF_NAME								PREF_PREFIX "/name"
#define PREF_PMSG								PREF_PREFIX "/pmsg"
#define PREF_NAME_MARKUP				PREF_PREFIX "/name-markup"
#define PREF_NAME_MARKUP_HOVER	PREF_PREFIX "/name-markup-hover"
#define PREF_PMSG_MARKUP				PREF_PREFIX "/pmsg-markup"
#define PREF_PMSG_MARKUP_HOVER	PREF_PREFIX "/pmsg-markup-hover"

//	Data structure
static PurplePluginUiInfo preferences = {
	preferences_make_window,
	0
};

//	Preferences methods
static PurplePluginPrefFrame *
preferences_make_window (PurplePlugin *plugin) {
	/** Makes the widget for selecting the preferences */
	PurplePluginPrefFrame *frame = purple_plugin_pref_frame_new ();
	PurplePluginPref *pref;
	// Select personal bar
	pref = purple_plugin_pref_new_with_name_and_label (PREF_PBAR, "Select personal bar");
	purple_plugin_pref_set_bounds (pref, 1, 2);
	purple_plugin_pref_frame_add (frame, pref);
	// Hide statusbox ?
	pref = purple_plugin_pref_new_with_name_and_label (PREF_STATUSBOX_HIDE, "Hide global status selector");
	purple_plugin_pref_frame_add (frame, pref);
	// Markup
	//	Name
	pref = purple_plugin_pref_new_with_name_and_label (PREF_NAME_MARKUP, "Name markup");
	purple_plugin_pref_frame_add (frame, pref);
	//	Name: hover
	pref = purple_plugin_pref_new_with_name_and_label (PREF_NAME_MARKUP_HOVER, "Name markup (hovered)");
	purple_plugin_pref_frame_add (frame, pref);
	//	Personal message
	pref = purple_plugin_pref_new_with_name_and_label (PREF_PMSG_MARKUP, "Personal message markup");
	purple_plugin_pref_frame_add (frame, pref);
	// Personal message: hover
	pref = purple_plugin_pref_new_with_name_and_label (PREF_PMSG_MARKUP_HOVER, "Personal message markup (hovered)");
	purple_plugin_pref_frame_add (frame, pref);
	// Return frame
	return frame;
}

void
preferences_init () {
	/** Creates and sets preferences */
	purple_prefs_add_none (PREF_PREFIX);
	//	Widget-wise
	purple_prefs_add_bool (PREF_STATUSBOX_HIDE, TRUE);
	purple_prefs_add_int (PREF_PBAR, 1); // 1:Craig's | 2:Wolter's
	//	Personal data
	purple_prefs_add_string (PREF_NAME, "<Display name>");
	purple_prefs_add_string (PREF_PMSG, "<Set your personal message>");
	//	Markup
	purple_prefs_add_string (PREF_NAME_MARKUP, "<big><b>%s</b></big>");
	purple_prefs_add_string (PREF_NAME_MARKUP_HOVER, "<span foreground=\"blue\"><big><b>%s</b></big></span>");
	purple_prefs_add_string (PREF_PMSG_MARKUP, "<small><i>%s</i></small>");
	purple_prefs_add_string (PREF_PMSG_MARKUP_HOVER, "<span foreground=\"blue\"><small><i>%s</i></small></span>");

	// Apply
	preferences_apply ();
}

void
preferences_apply () {
	/** Applies preferences */
	// Markup
	personal_bar.name_markup = strdup (purple_prefs_get_string (PREF_NAME_MARKUP));
	personal_bar.name_markup_hover = strdup (purple_prefs_get_string (PREF_NAME_MARKUP_HOVER));
	personal_bar.personal_message_markup = strdup (purple_prefs_get_string (PREF_PMSG_MARKUP));
	personal_bar.personal_message_markup_hover = strdup (purple_prefs_get_string (PREF_PMSG_MARKUP_HOVER));
	// Statusbox
	if (pidgin_interface.statusbox != NULL) {
		if (purple_prefs_get_bool (PREF_STATUSBOX_HIDE))
			gtk_widget_hide (GTK_WIDGET (pidgin_interface.statusbox));
		else
			gtk_widget_show (GTK_WIDGET (pidgin_interface.statusbox));
	}
}

// Plugin standard functions 
static void
init_plugin (PurplePlugin* plugin) {
	// This stupid function is needed by the plugin initializer
}

static gboolean
plugin_load (PurplePlugin* plugin) {
	/** Standard load method */
	personal_bar.plugin = plugin;
	signals_connect ();
	pidgin_interface_construct ();
	// Exit
	return TRUE;
}

static gboolean
plugin_unload (PurplePlugin* plugin) {
	/** Standard unload method */
	// Remove the personal bar
	personal_bar_uninstall ();
	// Exit
	return TRUE;
}

// Default plugin initiation method
PURPLE_INIT_PLUGIN (personal_bar, init_plugin, info);

// Plugin-wide signals connection
void
signals_connect () {
	/** Connects all purple signals */
	PurplePlugin *plugin = personal_bar.plugin;
	
	// Connect preference signals
	//	General
	purple_prefs_connect_callback (plugin, PREF_PBAR, personal_bar_install, NULL);
	purple_prefs_connect_callback (plugin, PREF_STATUSBOX_HIDE, preferences_apply, NULL);
	//	Name markup
	purple_prefs_connect_callback (plugin, PREF_NAME_MARKUP, preferences_apply, NULL);
	purple_prefs_connect_callback (plugin, PREF_NAME_MARKUP_HOVER, preferences_apply, NULL);
	//	Personal message markup
	purple_prefs_connect_callback (plugin, PREF_PMSG_MARKUP, preferences_apply, NULL);
	purple_prefs_connect_callback (plugin, PREF_PMSG_MARKUP_HOVER, preferences_apply, NULL);
	//	Buddy icon
	purple_prefs_connect_callback (plugin, PIDGIN_PREFS_ROOT "/accounts/buddyicon", global_buddy_icon_refresh, NULL);

	// Connect widget signals
	purple_signal_connect(pidgin_blist_get_handle(),
		"gtkblist-created",
		plugin,
		PURPLE_CALLBACK(pidgin_interface_construct),
		NULL);
	/*
	purple_signal_connect(purple_accounts_get_handle(),
			"account-status-changed",
			plugin,
			PURPLE_CALLBACK(status_update), NULL);
	*/
	purple_signal_connect(purple_connections_get_handle(),
			"signed-on",
			plugin,
			PURPLE_CALLBACK(status_online), NULL);
	purple_signal_connect(purple_connections_get_handle(),
			"signing-on",
			plugin,
			PURPLE_CALLBACK(status_signing_on), NULL);
	purple_signal_connect(purple_connections_get_handle(),
			"signing-off",
			plugin,
			PURPLE_CALLBACK(status_signing_off), NULL);
	/*
	purple_signal_connect(purple_accounts_get_handle(),
			"account-displayname-changed",
			plugin,
			PURPLE_CALLBACK(name_update), NULL);
	*/
}

// Common methods
void 
hover (GtkWidget *widget, gboolean setting) {
	/** Sets cursor as hand or arrow, depending on hover state */
	if (setting)
		pidgin_set_cursor (widget, GDK_HAND2);
	else
		pidgin_set_cursor (widget, GDK_ARROW);
}

void
stylize (GtkLabel *label, const char *markup) {
	/** Applies style to label based on html markup input */
	gtk_label_set_markup (label,
			g_markup_printf_escaped (markup,
					gtk_label_get_text (label)));
}

/* From GNOME Panel */
static void
do_colorshift (GdkPixbuf *dest, GdkPixbuf *src, int shift) {
	/** Gives a highlight to the pixbuf */
	gint i, j;
	gint width, height, has_alpha, srcrowstride, destrowstride;
	guchar *target_pixels;
	guchar *original_pixels;
	guchar *pixsrc;
	guchar *pixdest;
	int val;
	guchar r,g,b;

	has_alpha = gdk_pixbuf_get_has_alpha (src);
	width = gdk_pixbuf_get_width (src);
	height = gdk_pixbuf_get_height (src);
	srcrowstride = gdk_pixbuf_get_rowstride (src);
	destrowstride = gdk_pixbuf_get_rowstride (dest);
	target_pixels = gdk_pixbuf_get_pixels (dest);
	original_pixels = gdk_pixbuf_get_pixels (src);

	for (i = 0; i < height; i++) {
		pixdest = target_pixels + i*destrowstride;
		pixsrc = original_pixels + i*srcrowstride;
		for (j = 0; j < width; j++) {
			r = *(pixsrc++);
			g = *(pixsrc++);
			b = *(pixsrc++);
			val = r + shift;
			*(pixdest++) = CLAMP(val, 0, 255);
			val = g + shift;
			*(pixdest++) = CLAMP(val, 0, 255);
			val = b + shift;
			*(pixdest++) = CLAMP(val, 0, 255);
			if (has_alpha)
				*(pixdest++) = *(pixsrc++);
		}
	}
}

// Global data methods
void
global_name_get (GtkLabel *label) {
	/** Gets the global nickname */
	char *name;
	// Get from preference
	name = strdup (purple_prefs_get_string (PREF_NAME));
	purple_debug_info (PLUGIN_ID, "Global nickname is \"%s\".\n", name);
	// Set in personal_bar struct
	personal_bar.name = strdup (name);
	// Set in label, if not NULL
	if (label != NULL)
		gtk_label_set_text (label, name);
}

void
global_name_set (const char *name, GtkLabel *label) {
	/** Sets the nickname globally */
	// Set preference
	purple_prefs_set_string (PREF_NAME, name);
	purple_debug_info (PLUGIN_ID, "Global nickname set to \"%s\".\n", name);
	// Set in personal_bar struct
	personal_bar.name = strdup (name);
	// Represent in label, if not NULL
	if (label != NULL)
		gtk_label_set_text (label, name);
	// Set nickname for different protocols
	global_name_set_jabber ();
	global_name_set_msn ();
}

void
global_name_set_jabber () {
	/** Sets the jabber nickname */
	// Exit if there is no jabber account registered
	if (personal_bar.jabber_account == NULL) return;
	// Set the nickname
	//purple_debug_info (PLUGIN_ID, "Nickname set for Jabber account.\n");

	/* Code from original personalbar.c
	 * Please re-organize */
	
	/* http://xmpp.org/extensions/xep-0172.html#manage */
	/* XML stanza format to change xmpp nickname (PEP) 
		<iq from='narrator@moby-dick.lit/pda' type='set' id='pub1'>
			<pubsub xmlns='http://jabber.org/protocol/pubsub'>
				<publish node='http://jabber.org/protocol/nick'>
					<item>
					<nick xmlns='http://jabber.org/protocol/nick'>CallMeIshmael</nick>
					</item>
				</publish>
			</pubsub>
		</iq>

		Or use Pubsub Node
		<iq from='narrator@moby-dick.lit/pda' to='pubsub.mody-dick.lit' type='set' id='pub2'>
			<pubsub xmlns='http://jabber.org/protocol/pubsub'>
				<publish node='841f3c8955c4c41a0cf99620d78a33b996659ded'>
					<item>
					<nick xmlns='http://jabber.org/protocol/nick'>CallMeIshmael</nick>
					</item>
				</publish>
			</pubsub>
		</iq>
	*/
	//const char *id = purple_account_get_protocol_id(personal_bar.jabber_account);

	xmlnode *iq, *pubsub, *publish, *nicknode;

	iq = xmlnode_new("iq");
	xmlnode_set_attrib(iq, "from", g_strdup_printf("%s%s",
			purple_account_get_username(personal_bar.jabber_account), "laptop"));
//			 resource_name = jabber_get_resource(jbi->jid);
	xmlnode_set_attrib(iq, "type", "set");
	xmlnode_set_attrib(iq, "id", "pub1");
	pubsub = xmlnode_new("pubsub");
	xmlnode_set_attrib(pubsub, "xmlns", "http://jabber.org/protocol/pubsub");
	publish = xmlnode_new("publish");
	xmlnode_set_attrib(publish,"node","http://jabber.org/protocol/nick");
	nicknode = xmlnode_new_child(xmlnode_new_child(publish, "item"), "nick");
	xmlnode_set_namespace(nicknode, "http://jabber.org/protocol/nick");
	if (personal_bar.name) xmlnode_insert_data(nicknode, personal_bar.name, -1);
	xmlnode_insert_child(pubsub, publish);
	xmlnode_insert_child(iq, pubsub);		

	if (personal_bar.jabber_connection != NULL) {
		purple_debug_info(PLUGIN_ID, "Sending jabber info: %s\n", xmlnode_to_formatted_str(iq,NULL));
		//jabber_send(personal_bar.jabber_connection->proto_data, iq);
		purple_debug_info(PLUGIN_ID, "Finished sending jabber info\n");
	}
}

void
global_name_set_msn () {
	/** Sets the msn nickname */
	// Exit if there is no msn account registered
	if (personal_bar.msn_account == NULL) return;
	// Set the nickname
	purple_debug_info (PLUGIN_ID, "Nickname set for MSN account.\n");

	/* Code from original personalbar.c
	 * Please re-organize */
		GModule *module;
	typedef void (* MsnNickFunc) (PurpleConnection *gc, const char *entry);
	MsnNickFunc msn_act_id;

	if (g_module_supported()) {
#ifdef _WIN32
	const char *MSN_LIB;
	MSN_LIB = "";
	MSN_LIB = strcat(wpurple_lib_dir(), "/libmsn.dll");
#endif

/*#if GLIB_CHECK_VERSION(2,3,3)
		module = g_module_open(filename, G_MODULE_BIND_LOCAL);
#else
		module = g_module_open(filename, 0);
#endif
*/
		purple_debug_info(PLUGIN_ID, "Trying to open lib: %s\n", MSN_LIB);
		module = g_module_open(MSN_LIB, G_MODULE_BIND_LOCAL);
		if (module == NULL) {
			purple_debug_error(PLUGIN_ID, "module is NULL, error: %s\n", g_module_error ());
	      if (!g_module_close (module))
				purple_debug_error(PLUGIN_ID, "Could not close NULL module: %s, error: %s\n", MSN_LIB, g_module_error ());
				g_warning ("%s: %s", MSN_LIB, g_module_error ());
		}
		else {
			if (g_module_symbol(module, "msn_act_id", (gpointer *)&msn_act_id)) {
				purple_debug_info(PLUGIN_ID, "Loading msn_act_id\n");
				msn_act_id(personal_bar.msn_connection, personal_bar.name);
				if (!g_module_close (module)) g_warning ("Could not close %s, error: %s", MSN_LIB, g_module_error ());
			}
			else {
				purple_debug_error(PLUGIN_ID, "Error calling g_module_symbol on %s, error: %s\n", MSN_LIB, g_module_error ());
				if (!g_module_close (module))
						g_warning ("%s: %s", MSN_LIB, g_module_error ());
			}
		}

	}
	else purple_debug_error(PLUGIN_ID, "gmodule not supported!\n");
}

void
global_pmsg_get (GtkLabel *label) {
	/** Gets the personal message from a preference and sets it into a label */
	char *pmsg;
	// Get the text
	pmsg = strdup (purple_prefs_get_string (PREF_PMSG));
	purple_debug_info (PLUGIN_ID, "Global personal message is \"%s\".\n", pmsg);
	// Set it in the personal_bar struct
	personal_bar.personal_message = strdup (pmsg);
	// Set it in the label, if not null
	if (label != NULL)
		gtk_label_set_text (label,
		strcmp (pmsg, "") ? pmsg : EMPTY_MESSAGE);
}

void
global_pmsg_set (const char *pmsg, GtkLabel *label) {
	/** Sets the personal message globally */
	// Set preference
	purple_prefs_set_string (PREF_PMSG, pmsg);
	purple_debug_info (PLUGIN_ID, "Global personal message set to \"%s\".\n", pmsg);
	// Set in personal_bar struct
	personal_bar.personal_message = strdup (pmsg);
	// Represent in label, if not NULL
	if (label != NULL)
		gtk_label_set_text (label,
			strcmp (pmsg, "") ? pmsg : EMPTY_MESSAGE);
	// Set personal message for all protocols
}

void
global_buddy_icon_refresh () {
	/** Refreshes the buddy icon when it gets changed */
	// Refresh for installed personal bar
	if (personal_bar_c_interface.installed)
		personal_bar_c_interface.buddy_icon_refresh ();
	else if (personal_bar_w_interface.installed)
		personal_bar_w_interface.buddy_icon_refresh ();
}

void
global_buddy_icon_select_dummy (const char *path, gpointer data) {
	/** Sets the buddy icon path to path */
	if (path != NULL)
		purple_prefs_set_path (PIDGIN_PREFS_ROOT "/accounts/buddyicon", path);
}

void
global_buddy_icon_select () {
	/** Selects and sets the buddy icon globally */
	GtkWidget *filechooser = pidgin_buddy_icon_chooser_new (
			GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (pidgin_interface.blist))),
			global_buddy_icon_select_dummy,
			NULL); //pidgin_interface.statusbox);
	gtk_widget_show (filechooser);
}

// Pidgin Interface construct
void
pidgin_interface_construct () {
	/** Assigns pointers to pidgin's widgets for future usage */
	pidgin_interface.blist = pidgin_blist_get_default_gtk_blist();
	pidgin_interface.statusbox = PIDGIN_STATUS_BOX (pidgin_interface.blist->statusbox);
	// Install the personal bar
	personal_bar_install ();
}

// Personal bar methods
void
personal_bar_init () {
	/** Initializes the common personal_bar struct */
	// Preferences
	preferences_init ();
	// Get accounts
	personal_bar_get_accounts ();
}

void
personal_bar_get_accounts () {
	GList *connections = purple_accounts_get_all_active ();
	PurpleAccount *account;
	GList *accounts_list;
	char *account_id;

		#define PURPLE_MSN_ID "prpl-msn"
		#define PURPLE_JABBER_ID "prpl-jabber"

	for (accounts_list = connections;
			accounts_list != NULL;
			accounts_list = accounts_list->next) {
		account = accounts_list->data;
		account_id = strdup (purple_account_get_protocol_id (account));
		if (purple_account_is_connected (account)) {
			if (strcmp (account_id, PURPLE_MSN_ID) == 0) {
				purple_debug_info (PLUGIN_ID, "Found MSN account.\n");
				personal_bar.msn_account = account;
				personal_bar.msn_connection = purple_account_get_connection (personal_bar.msn_account);
				global_name_set_msn ();
				//global_pmsg_set_msn ();
			}
			else if (strcmp (account_id, PURPLE_JABBER_ID) == 0) {
				purple_debug_info (PLUGIN_ID, "Found Jabber account.\n");
				personal_bar.jabber_account = account;
				personal_bar.jabber_connection = purple_account_get_connection (personal_bar.jabber_account);
				global_name_set_jabber ();
				//global_pmsg_set_jabber ();
			}
			else {
				purple_debug_info (PLUGIN_ID,
						"Found unsupported account with id \"%s\".\n",
						account_id);
			}
		}
	}
}

void
personal_bar_install () {
	/** Starts the preferred personal bar */
	// Remove any previously installed personal bar
	personal_bar_uninstall ();
	// Set shared attributes
	personal_bar_init ();
	// Install preferred personal bar
	if (purple_prefs_get_int (PREF_PBAR) == 1)
		personal_bar_c_install ();
	else if (purple_prefs_get_int (PREF_PBAR) == 2)
		personal_bar_w_install ();
}

void
personal_bar_uninstall () {
	/** Removes the previously started personal bar */
	// Remove the personal bar
		// Check if Craig's is installed
	if (personal_bar_c_interface.installed == TRUE)
		personal_bar_c_uninstall ();
		// Check if Wolter's is installed
	if (personal_bar_w_interface.installed == TRUE)
		personal_bar_w_uninstall ();
	// Show the Statusbox, if hidden
	gtk_widget_show (GTK_WIDGET (pidgin_interface.statusbox));
}

// Craig's personal bar methods
void
personal_bar_c_install () {
	/** Install Craig's personal bar */
	struct _personal_bar_c_interface *pb = &personal_bar_c_interface;
	// Make widgets
	//	Containers
	pb->hbox = gtk_hbox_new (FALSE, 2);
	pb->vbox = gtk_vbox_new (FALSE, 0);
	pb->name_and_status_box = gtk_hbox_new (FALSE, 2);
	//	Buddy Icon
	pb->buddy_icon = gtk_image_new ();
	pb->buddy_icon_event_box = gtk_event_box_new ();
		gtk_event_box_set_visible_window (GTK_EVENT_BOX (pb->buddy_icon_event_box), FALSE);
	//	Name label
	pb->name_label = gtk_label_new (NULL);
	pb->name_button = gtk_button_new ();
		gtk_button_set_relief (GTK_BUTTON (pb->name_button), GTK_RELIEF_NONE);
		gtk_widget_set_can_focus (pb->name_button, FALSE);
	//	Name entry
	pb->name_entry = gtk_entry_new ();
	//	Status
	pb->status_button = gtk_button_new_with_label ("(Connecting...)");
		gtk_widget_set_can_focus (pb->status_button, FALSE);
		gtk_button_set_relief (GTK_BUTTON (pb->status_button), GTK_RELIEF_NONE);
	//	Personal Message
	pb->personal_message_label = gtk_label_new ("Personal message");
	pb->personal_message_button = gtk_button_new ();
		gtk_button_set_relief (GTK_BUTTON (pb->personal_message_button), GTK_RELIEF_NONE);
		gtk_widget_set_can_focus (pb->personal_message_button, FALSE);
	//	Personal message entry
	pb->personal_message_entry = gtk_entry_new ();
	
	// Install widgets
	//	Pack stuff into containers
	gtk_container_add (GTK_CONTAINER (pb->buddy_icon_event_box),
			pb->buddy_icon);
	gtk_container_add (GTK_CONTAINER (pb->name_button),
			pb->name_label);
	gtk_container_add (GTK_CONTAINER (pb->personal_message_button),
			pb->personal_message_label);
	#define PACKING_OPTIONS TRUE, TRUE, 0
	//	Pack name and status button into name_and_status_box
	gtk_box_pack_start (GTK_BOX (pb->name_and_status_box),
			pb->name_button, PACKING_OPTIONS);
	gtk_box_pack_start (GTK_BOX (pb->name_and_status_box),
			pb->name_entry, PACKING_OPTIONS);
	gtk_box_pack_start (GTK_BOX (pb->name_and_status_box),
			pb->status_button, FALSE, FALSE, 0);
	//	Pack name_and_status and personal message into vbox
	gtk_box_pack_start (GTK_BOX (pb->vbox),
			pb->name_and_status_box, PACKING_OPTIONS);
	gtk_box_pack_start (GTK_BOX (pb->vbox),
			pb->personal_message_button, PACKING_OPTIONS);
	gtk_box_pack_start (GTK_BOX (pb->vbox),
			pb->personal_message_entry, PACKING_OPTIONS);
	//	Pack buddy icon and the rest into hbox
	gtk_box_pack_start (GTK_BOX (pb->hbox),
			pb->buddy_icon_event_box, FALSE, FALSE, 5);
	gtk_box_pack_start (GTK_BOX (pb->hbox),
			pb->vbox, PACKING_OPTIONS);
	//	Pack all into buddy list
	gtk_box_pack_start (GTK_BOX (pidgin_interface.blist->vbox),
			pb->hbox, FALSE, TRUE, 2);
	gtk_box_reorder_child (GTK_BOX (pidgin_interface.blist->vbox),
			pb->hbox, 0);
	// Connect signals
	personal_bar_c_signals_connect ();
	// Perform initial actions
	pb->buddy_icon_refresh ();
	global_name_get (GTK_LABEL (pb->name_label));
	pb->name_label_unhovered ();
	global_pmsg_get (GTK_LABEL (pb->personal_message_label));
	pb->personal_message_label_unhovered ();
	// Show all
	gtk_widget_show_all (pb->hbox);
	gtk_widget_hide (pb->name_entry);
	gtk_widget_hide (pb->personal_message_entry);
	// Set and inform
	pb->installed = TRUE;
	purple_debug_info (PLUGIN_ID, "Craig's personal bar installed.\n");
}

void
personal_bar_c_signals_connect () {
	/** Connect signals for Craig's personal bar */
	struct _personal_bar_c_interface *pb = &personal_bar_c_interface;
	// Connect the signals
	//	Buddy Icon
	g_signal_connect (G_OBJECT (pb->buddy_icon_event_box),
			"button-press-event",
			G_CALLBACK (pb->buddy_icon_clicked), NULL);
	g_signal_connect (G_OBJECT (pb->buddy_icon_event_box),
			"enter-notify-event",
			G_CALLBACK (pb->buddy_icon_hovered), NULL);
	g_signal_connect (G_OBJECT (pb->buddy_icon_event_box),
			"leave-notify-event",
			G_CALLBACK (pb->buddy_icon_unhovered), NULL);
	//	Name label
	g_signal_connect (G_OBJECT (pb->name_button),
			"clicked",
			G_CALLBACK (pb->name_label_clicked), NULL);
	g_signal_connect (G_OBJECT (pb->name_button),
			"enter",
			G_CALLBACK (pb->name_label_hovered), NULL);
	g_signal_connect (G_OBJECT (pb->name_button),
			"leave",
			G_CALLBACK (pb->name_label_unhovered), NULL);
	//	Name entry
	g_signal_connect (G_OBJECT (pb->name_entry),
			"activate",
			G_CALLBACK (pb->name_entry_deactivate), NULL);
	g_signal_connect (G_OBJECT (pb->name_entry),
			"focus-out-event",
			G_CALLBACK (pb->name_entry_deactivate), NULL);
	//	Status
	purple_signal_connect (purple_accounts_get_handle (),
			"account-status-changed",
			personal_bar.plugin,
			PURPLE_CALLBACK (pb->status_button_update), NULL);
	g_signal_connect (G_OBJECT (pb->status_button),
			"clicked",
			G_CALLBACK (pb->status_button_clicked), NULL);
	//	Personal message
	g_signal_connect (G_OBJECT (pb->personal_message_button),
			"clicked",
			G_CALLBACK (pb->personal_message_label_clicked), NULL);
	g_signal_connect (G_OBJECT (pb->personal_message_button),
			"enter",
			G_CALLBACK (pb->personal_message_label_hovered), NULL);
	g_signal_connect (G_OBJECT (pb->personal_message_button),
			"leave",
			G_CALLBACK (pb->personal_message_label_unhovered), NULL);
	//	Personal message entry
	g_signal_connect (G_OBJECT (pb->personal_message_entry),
			"activate",
			G_CALLBACK (pb->personal_message_entry_deactivate), NULL);
	g_signal_connect (G_OBJECT (pb->personal_message_entry),
			"focus-out-event",
			G_CALLBACK (pb->personal_message_entry_deactivate), NULL);
	// Connect callbacks
	personal_bar_c_callbacks_connect ();
}

void
personal_bar_c_callbacks_connect () {
	/** Connects functions pointers with signal callbacks
	 * for Craig's personal bar */
	struct _personal_bar_c_interface *pb = &personal_bar_c_interface;
	// Buddy icon signal callbacks
	pb->buddy_icon_refresh = c_bir;
	pb->buddy_icon_clicked = c_bic;
	pb->buddy_icon_hovered = c_bih;
	pb->buddy_icon_unhovered = c_biu;
	// Name label
	pb->name_label_clicked = c_nlc;
	pb->name_label_hovered = c_nlh;
	pb->name_label_unhovered = c_nlu;
	// Name entry
	pb->name_entry_activate = c_nea;
	pb->name_entry_deactivate = c_ned;
	// Status button
	pb->status_button_update = c_sbu;
	pb->status_button_clicked = c_sbc;
	// Personal message label
	pb->personal_message_label_clicked = c_pmlc;
	pb->personal_message_label_hovered = c_pmlh;
	pb->personal_message_label_unhovered = c_pmlu;
	// Personal message entry
	pb->personal_message_entry_activate = c_pmea;
	pb->personal_message_entry_deactivate = c_pmed;
}

void
personal_bar_c_uninstall () {
	/** Uninstalls Craig's personal bar */
	// Destroy everything
	GList *list, *iter;
	list = gtk_container_get_children (GTK_CONTAINER (personal_bar_c_interface.hbox));
	for (iter = list; iter != NULL; iter = iter->next) {
		gtk_widget_destroy (iter->data);
		iter->data = NULL;
	}
	gtk_widget_destroy (personal_bar_c_interface.hbox);
	// Inform
	purple_debug_info (PLUGIN_ID, "Craig's personal bar destroyed.\n");
	// Set as uninstalled
	personal_bar_c_interface.installed = FALSE;
}

// Wolter's personal bar methods
void
personal_bar_w_install () {
	/** Install Wolter's personal bar */
	struct _personal_bar_w_interface *pb = &personal_bar_w_interface;
	// Construct the personal bar
	//	Containers
	pb->hbox = gtk_hbox_new (FALSE, 1);
	pb->vbox = gtk_vbox_new (FALSE, 1);
	//	Buddy Icon
	pb->buddy_icon = gtk_button_new ();
		gtk_widget_set_size_request (pb->buddy_icon, 60, 60);
		gtk_widget_set_can_focus (pb->buddy_icon, FALSE);
	//	Name label
	pb->name_label = gtk_label_new (NULL);
	pb->name_button = gtk_button_new ();
		gtk_widget_set_can_focus (pb->name_button, FALSE);
	// Name entry
	pb->name_entry = gtk_entry_new ();
	//	Statusbox
	pb->statusbox = pidgin_status_box_new ();
		// Hides icon
		g_object_set (pb->statusbox,
				"iconsel",
				FALSE,
				NULL);

	// Install widgets
	//	Pack all into personal bar
	#define PACKING_OPTIONS TRUE, TRUE, 0
	gtk_box_pack_start (GTK_BOX (pb->hbox), pb->buddy_icon, FALSE, FALSE, 0);
	gtk_container_add (GTK_CONTAINER (pb->name_button),
			GTK_WIDGET (pb->name_label));
	gtk_box_pack_start (GTK_BOX (pb->vbox), pb->name_button, PACKING_OPTIONS);
	gtk_box_pack_start (GTK_BOX (pb->vbox), pb->name_entry, PACKING_OPTIONS);
	gtk_box_pack_start (GTK_BOX (pb->vbox), pb->statusbox, FALSE, TRUE, 0);
	gtk_box_pack_start (GTK_BOX (pb->hbox), pb->vbox, PACKING_OPTIONS);
	//	Pack personal bar into buddy list
	gtk_box_pack_start (GTK_BOX (pidgin_interface.blist->vbox),
			pb->hbox, FALSE, TRUE, 2);
	//	Allocate in the top of the buddy list
	gtk_box_reorder_child (GTK_BOX (pidgin_interface.blist->vbox),
			pb->hbox, 0);
	// Connect signals
	personal_bar_w_signals_connect ();
	// Perform initial actions
	pb->buddy_icon_refresh ();
	global_name_get (GTK_LABEL (pb->name_label));
	pb->name_label_unhovered ();
	// Show all
	gtk_widget_show_all (pb->hbox);
	gtk_widget_hide (pb->name_entry);
	// Set and inform
	pb->installed = TRUE;
	purple_debug_info (PLUGIN_ID, "Wolter's personal bar installed.\n");
}

void
personal_bar_w_signals_connect () {
	/** Connects signals for Wolter's personal bar */
	struct _personal_bar_w_interface *pb = &personal_bar_w_interface;
	// Buddy icon
	g_signal_connect (G_OBJECT (pb->buddy_icon),  
			"clicked",
			G_CALLBACK (pb->buddy_icon_clicked), NULL);
	// Name label
	g_signal_connect (G_OBJECT (pb->name_button),
			"clicked",
			G_CALLBACK (pb->name_label_clicked), NULL);
	g_signal_connect (G_OBJECT (pb->name_button),
			"enter",
			G_CALLBACK (pb->name_label_hovered), NULL);
	g_signal_connect (G_OBJECT (pb->name_button),
			"leave",
			G_CALLBACK (pb->name_label_unhovered), NULL);
	// Name entry
	g_signal_connect (G_OBJECT (pb->name_entry),
			"activate",
			G_CALLBACK (pb->name_entry_deactivate), NULL);
	g_signal_connect (G_OBJECT (pb->name_entry),
			"focus-out-event",
			G_CALLBACK (pb->name_entry_deactivate), NULL);
	// Connect callbacks
	personal_bar_w_callbacks_connect ();
}

void
personal_bar_w_callbacks_connect () {
	/** Connects function pointers with functions for
	 * for Wolter's personal bar */
	struct _personal_bar_w_interface *pb = &personal_bar_w_interface;
	pb->buddy_icon_refresh = w_bir;
	pb->buddy_icon_clicked = w_bic;
	pb->name_label_clicked = w_nlc;
	pb->name_label_hovered = w_nlh;
	pb->name_label_unhovered = w_nlu;
	pb->name_entry_activate = w_nea;
	pb->name_entry_deactivate = w_ned;
}

void
personal_bar_w_uninstall () {
	/** Uninstalls Wolter's personal bar */
	// Destroy everything
	GList *list, *iter;
	list = gtk_container_get_children (GTK_CONTAINER (personal_bar_w_interface.hbox));
	for (iter = list; iter != NULL; iter = iter->next) {
		gtk_widget_destroy (iter->data);
		iter->data = NULL;
	}
	gtk_widget_destroy (personal_bar_w_interface.hbox);
	// Inform
	purple_debug_info (PLUGIN_ID, "Wolter's personal bar destroyed.\n");
	// Set as uninstalled
	personal_bar_w_interface.installed = FALSE;
}

// General callbacks
void
name_update () {
	/** Callback for when the name has been changed */
	purple_debug_info (PLUGIN_ID, "Name updated.\n");
}

void
status_update () {
	/** Callback for when the status has been changed */
	purple_debug_info (PLUGIN_ID, "Status updated.\n");
}

void
status_online () {
	/** Callback for when status is online */
	purple_debug_info (PLUGIN_ID, "Status: online.\n");
	personal_bar_get_accounts ();
}

void
status_signing_on () {
	/** Callback for when status is signing on */
	purple_debug_info (PLUGIN_ID, "Status: signing on...\n");
}

void
status_signing_off () {
	/** Callback for when status is signing off */
	purple_debug_info (PLUGIN_ID, "Status: signing off...\n");
}

// Craig's callbacks
void
c_bir () {
	/** (Craig) Callback to refresh [Buddy icon] */
	purple_debug_info (PLUGIN_ID, "[Buddy icon] refreshed.\n");
	struct _personal_bar_c_interface *pb = &personal_bar_c_interface;
	// Verify that statusbox is not NULL to prevent segfault
	if (pidgin_interface.statusbox != NULL) {
		pb->buddy_icon_pixbuf = pidgin_interface.statusbox->buddy_icon;
		//pb->buddy_icon_pixbuf = gdk_pixbuf_scale_simple (pb->buddy_icon_pixbuf, 48, 48, GDK_INTERP_BILINEAR);
		// [v] Not working, fix later
		//pidgin_gdk_pixbuf_make_round (pb->buddy_icon_pixbuf);
		gtk_image_set_from_pixbuf (GTK_IMAGE (pb->buddy_icon),
				pb->buddy_icon_pixbuf);
	}
	else {
		gtk_image_set_from_stock (GTK_IMAGE (pb->buddy_icon),
				GTK_STOCK_MISSING_IMAGE, 48);
	}
}

void
c_bic () {
	/** (Craig) Callback for when [Buddy icon] is clicked */
	purple_debug_info (PLUGIN_ID, "[Buddy icon] clicked.\n");
	// Select buddy icon
	global_buddy_icon_select ();
	// Set it
	personal_bar_c_interface.buddy_icon_refresh ();
}

void
c_bih () {
	/** (Craig) Callback for when [Buddy icon] is hovered */
	purple_debug_info (PLUGIN_ID, "[Buddy icon] hovered.\n");
	struct _personal_bar_c_interface *pb = &personal_bar_c_interface;
	// Increase value in image
	pb->buddy_icon_pixbuf_hovered = gdk_pixbuf_copy (pb->buddy_icon_pixbuf);
	do_colorshift (pb->buddy_icon_pixbuf_hovered, pb->buddy_icon_pixbuf_hovered, 32);
	gtk_image_set_from_pixbuf (GTK_IMAGE (pb->buddy_icon), pb->buddy_icon_pixbuf_hovered);
	// Change cursor
	hover (pb->buddy_icon_event_box, TRUE);
}

void
c_biu () {
	/** (Craig) Callback for when [Buddy icon] is unhovered */
	struct _personal_bar_c_interface *pb = &personal_bar_c_interface;
	purple_debug_info (PLUGIN_ID, "[Buddy icon] unhovered.\n");
	// Restore original image (and its value)
	pb->buddy_icon_refresh ();
	// Restore cursor
	hover (pb->buddy_icon_event_box, FALSE);
}

void
c_nlc () {
	/** (Craig) Callback for when [Name label] is clicked */
	purple_debug_info (PLUGIN_ID, "[Name label] clicked.\n");
	// Activate [Name entry]
	personal_bar_c_interface.name_entry_activate ();
}

void
c_nlh () {
	/** (Craig) Callback for when [Name label] is hovered */
	purple_debug_info (PLUGIN_ID, "[Name label] hovered.\n");
	// Give hover style
	stylize (GTK_LABEL (personal_bar_c_interface.name_label),
			personal_bar.name_markup_hover);
}

void
c_nlu () {
	/** (Craig) Callback for when [Name label] is unhovered */
	purple_debug_info (PLUGIN_ID, "[Name label] unhovered.\n");
	// Restore style
	stylize (GTK_LABEL (personal_bar_c_interface.name_label),
			personal_bar.name_markup);
}

void
c_nea () {
	/** (Craig) Callback to activate [Name entry] */
	purple_debug_info (PLUGIN_ID, "[Name entry] activated.\n");
	struct _personal_bar_c_interface *pb = &personal_bar_c_interface;
	// Hide and show
	gtk_widget_hide (pb->name_button);
	gtk_widget_show (pb->name_entry);
	// Prepare [Name entry]
	gtk_entry_set_text (GTK_ENTRY (pb->name_entry),
			gtk_label_get_text (GTK_LABEL (pb->name_label)));
	gtk_widget_grab_focus (pb->name_entry);
}

void
c_ned () {
	/** (Craig) Callback to deactivate [Name entry] */
	purple_debug_info (PLUGIN_ID, "[Name entry] deactivated.\n");
	struct _personal_bar_c_interface *pb = &personal_bar_c_interface;
	// Set nickname at global level
	char *name = strdup (gtk_entry_get_text (GTK_ENTRY (pb->name_entry)));
	global_name_set (name, GTK_LABEL (pb->name_label));
	pb->name_label_unhovered ();
	// Hide and show
	gtk_widget_hide (pb->name_entry);
	gtk_widget_show (pb->name_button);	
}

void
c_sbu (PurpleAccount *account, PurpleStatus *old, PurpleStatus *new) {
	/** (Craig) Callback for when status is updated */
	GString *status = g_string_new (purple_status_get_name (new));
	g_string_prepend (status, "(");
	g_string_append (status, ")");
	purple_debug_info (PLUGIN_ID, "[Status button]'s status updated.\n");
	gtk_button_set_label (GTK_BUTTON (personal_bar_c_interface.status_button),
			status->str);
}

void
c_sbc () {
	/** (Craig) Callback for when [Status button] is clicked */
	purple_debug_info (PLUGIN_ID, "[Status button] clicked.\n");
}

void
c_pmlc () {
	/** (Craig) Callback for when [Personal message label] is clicked */
	purple_debug_info (PLUGIN_ID, "[Personal message label] clicked.\n");
	// Activate [Personal message entry]
	personal_bar_c_interface.personal_message_entry_activate ();
}

void
c_pmlh () {
	/** (Craig) Callback for when [Personal message label] is hovered */
	purple_debug_info (PLUGIN_ID, "[Personal message label] hovered.\n");
	// Give hover style
	stylize (GTK_LABEL (personal_bar_c_interface.personal_message_label),
			personal_bar.personal_message_markup_hover);
}

void
c_pmlu () {
	/** (Craig) Callback for when [Personal message label] is unhovered */
	purple_debug_info (PLUGIN_ID, "[Personal message label] unhovered.\n");
	// Restore style
	stylize (GTK_LABEL (personal_bar_c_interface.personal_message_label),
			personal_bar.personal_message_markup);
}

void
c_pmea () {
	/** (Craig) Callback to activate [Personal message entry] */
	purple_debug_info (PLUGIN_ID, "[Personal message entry] activated.\n");
	struct _personal_bar_c_interface *pb = &personal_bar_c_interface;
	// Hide and show
	gtk_widget_hide (pb->personal_message_button);
	gtk_widget_show (pb->personal_message_entry);
	// Prepare [Personal message entry]
	char *pmsg = strdup (gtk_label_get_text (GTK_LABEL (pb->personal_message_label)));
	gtk_entry_set_text (GTK_ENTRY (pb->personal_message_entry),
			strcmp (pmsg, EMPTY_MESSAGE) ? pmsg : "");
	gtk_widget_grab_focus (pb->personal_message_entry);
}

void
c_pmed () {
	/** (Craig) Callback to deactivate [Personal message entry] */
	purple_debug_info (PLUGIN_ID, "[Personal message entry] deactivated.\n");
	struct _personal_bar_c_interface *pb = &personal_bar_c_interface;
	// Prepare [Personal message label]
	global_pmsg_set (gtk_entry_get_text (GTK_ENTRY (pb->personal_message_entry)),
			GTK_LABEL (pb->personal_message_label));
	pb->personal_message_label_unhovered ();
	// Hide and show
	gtk_widget_hide (pb->personal_message_entry);
	gtk_widget_show (pb->personal_message_button);
}

// Wolter's callbacks
void
w_bir () {
	/** (Wolter) Callback to refresh [Buddy icon] */
	struct _personal_bar_w_interface *pb = &personal_bar_w_interface;
	char *img_path = strdup (purple_prefs_get_path (PIDGIN_PREFS_ROOT "/accounts/buddyicon"));
	if ((pidgin_interface.statusbox != NULL) && (img_path != NULL)) {
		pb->buddy_icon_pixbuf = gdk_pixbuf_new_from_file (img_path, NULL);
		// Consider image proportions
		int width, height;
		width = gdk_pixbuf_get_width (pb->buddy_icon_pixbuf);
		height = gdk_pixbuf_get_height (pb->buddy_icon_pixbuf);
		if (width > height) {
			height = (int) 48*((float) height/(float) width);
			width = 48;
		}
		else if (width < height) {
			width = (int) 48*((float) width/(float) height);
			height = 48;
		}
		else {
			width = 48;
			height = 48;
		}
		purple_debug_info (PLUGIN_ID, "Width: %d | Height: %d.\n", width, height);
		// Scale according to proportions
		pb->buddy_icon_pixbuf = gdk_pixbuf_scale_simple (pb->buddy_icon_pixbuf,
				abs (width), abs (height),
				GDK_INTERP_BILINEAR);
		gtk_button_set_image (GTK_BUTTON (pb->buddy_icon), gtk_image_new_from_pixbuf (pb->buddy_icon_pixbuf));
	}
	else {
		gtk_button_set_image (GTK_BUTTON (pb->buddy_icon),
				gtk_image_new_from_stock (GTK_STOCK_MISSING_IMAGE, 48));
	}
}

void
w_bic () {
	/** (Wolter) Callback for when [Buddy icon] is clicked */
	purple_debug_info (PLUGIN_ID, "[Buddy icon] clicked.\n");
	// Select buddy icon
	global_buddy_icon_select ();
	// Set it
	personal_bar_w_interface.buddy_icon_refresh ();
}

void
w_nlc () {
	/** (Wolter) Callback for when [Name label] is clicked */
	purple_debug_info (PLUGIN_ID, "[Name label] clicked.\n");
	// Activate [Name entry]
	personal_bar_w_interface.name_entry_activate ();
}

void
w_nlh () {
	/** (Wolter) Callback for when [Name label] is hovered */
	purple_debug_info (PLUGIN_ID, "[Name label] hovered.\n");
	struct _personal_bar_w_interface *pb = &personal_bar_w_interface;
	// Give hover style
	stylize (GTK_LABEL (pb->name_label), personal_bar.name_markup_hover);
	gtk_button_set_relief (GTK_BUTTON (pb->name_button), GTK_RELIEF_NORMAL);
	// Change cursor
	//hover (pb->name_button, TRUE);
}

void
w_nlu () {
	/** (Wolter) Callback for when [Name label] is unhovered */
	purple_debug_info (PLUGIN_ID, "[Name label] unhovered.\n");
	struct _personal_bar_w_interface *pb = &personal_bar_w_interface;
	// Restore style
	stylize (GTK_LABEL (pb->name_label), personal_bar.name_markup);
	gtk_button_set_relief (GTK_BUTTON (pb->name_button), GTK_RELIEF_NONE);
	// Restore cursor
	//hover (pb->name_button, FALSE);
}

void 
w_nea () {
	/** (Wolter) Callback to activate [Name entry] */
	purple_debug_info (PLUGIN_ID, "[Name entry] activated.\n");
	struct _personal_bar_w_interface *pb = &personal_bar_w_interface;
	// Hide [Name label] and show
	gtk_widget_hide (pb->name_button);
	gtk_widget_show (pb->name_entry);
	// Prepare [Name entry]
	gtk_entry_set_text (GTK_ENTRY (pb->name_entry),
			gtk_label_get_text (GTK_LABEL (pb->name_label)));
	gtk_widget_grab_focus (pb->name_entry);
}

void
w_ned () {
	/** (Wolter) Callback to deactivate [Name entry] */
	purple_debug_info (PLUGIN_ID, "[Name entry] deactivated.\n");
	struct _personal_bar_w_interface *pb = &personal_bar_w_interface;
	// Prepare [Name label]
	char *name = strdup (gtk_entry_get_text (GTK_ENTRY (pb->name_entry)));
	//	Set nickname at global level
	global_name_set (name, GTK_LABEL (pb->name_label));
	pb->name_label_unhovered ();
	// Hide and show [Name label]
	gtk_widget_hide (pb->name_entry);
	gtk_widget_show (pb->name_button);
}
